// Hook.cpp : Defines the exported functions for the DLL application.
//

#include "stdafx.h"

// shared data
#pragma data_seg(".SHRDATA")
HWND s_hWndServer = NULL;
HookConf s_sHookConf = {NULL};
HHOOK s_hhkMouse = NULL;
HHOOK s_hhkKeyboard = NULL;
TCHAR s_tCurrFileName[MAX_PATH] = {NULL};

DWORD s_dwCurrProcId = 0;
BOOL s_bHookingMouse = TRUE;
BOOL s_bHookingKeyboard = TRUE;

Record s_tBufIo[BUF_IO_SIZE/sizeof(Record)] = {{NULL}};
unsigned s_uBufRecCount = 0;
#if 0
const TCHAR s_strButtons[(WM_MOUSELAST - WM_MOUSEFIRST) * 2][7] = 
{
	_T("MOVE"),
	_T("L_DOWN"), _T("L_UP"), _T("L_DBL"),
	_T("R_DOWN"), _T("R_UP"), _T("R_DBL"),
	_T("M_DOWN"), _T("M_UP"), _T("M_DBL"),
	_T("X_DOWN"), _T("X_UP"), _T("X_DBL"),
	_T("MOVE"),
	_T("L_DOWN"), _T("L_UP"), _T("L_DBL"),
	_T("R_DOWN"), _T("R_UP"), _T("R_DBL"),
	_T("M_DOWN"), _T("M_UP"), _T("M_DBL"),
	_T("X_DOWN"), _T("X_UP"), _T("X_DBL")
};
const TCHAR s_strKeys[0xFF + 1][20] = 
{
	/*
	* Virtual Keys, Standard Set
	*/
	_T("unassigned"),    //
	_T("LBUTTON"),       //        0x01
	_T("RBUTTON"),       //        0x02
	_T("CANCEL"),        //        0x03
	_T("MBUTTON"),       //        0x04    /* NOT contiguous with L & RBUTTON */

	_T("XBUTTON1"),      //       0x05    /* NOT contiguous with L & RBUTTON */
	_T("XBUTTON2"),      //       0x06    /* NOT contiguous with L & RBUTTON */
	/*
	* 0x07 : unassigned
	*/
	_T("unassigned"),    //

	_T("BACK"),          //           0x08
	_T("TAB"),           //            0x09
	/*
	* 0x0A - 0x0B : reserved
	*/
	_T("reserved"),  //
	_T("reserved"),  //

	_T("CLEAR"), //          0x0C
	_T("RETURN"),    //         0x0D

	_T("unassigned"),    //
	_T("unassigned"),    //

	_T("SHIFT"), //          0x10
	_T("CONTROL"),   //        0x11
	_T("MENU"),  //           0x12
	_T("PAUSE"), //          0x13
	_T("CAPITAL"),   //        0x14

	_T("KANA"),  //           0x15
	//_T("HANGEUL"),   //        0x15  /* old name - should be here for compatibility */
	//_T("HANGUL"),    //         0x15
	_T("reserved"),  //
	_T("JUNJA"), //          0x17
	_T("FINAL"), //          0x18
	_T("HANJA/KANJI"), //          0x19
	//_T("KANJI"), //          0x19
	_T("reserved"),  //

	_T("ESCAPE"),    //         0x1B

	_T("CONVERT"),   //        0x1C
	_T("NONCONVERT"),    //     0x1D
	_T("ACCEPT"),    //         0x1E
	_T("MODECHANGE"),    //     0x1F

	_T("SPACE"), //          0x20
	_T("PRIOR"), //          0x21
	_T("NEXT"),  //           0x22
	_T("END"),   //            0x23
	_T("HOME"),  //           0x24
	_T("LEFT"),  //           0x25
	_T("UP"),    //             0x26
	_T("RIGHT"), //          0x27
	_T("DOWN"),  //           0x28
	_T("SELECT"),    //         0x29
	_T("PRINT"), //          0x2A
	_T("EXECUTE"),   //        0x2B
	_T("SNAPSHOT"),  //       0x2C
	_T("INSERT"),    //         0x2D
	_T("DELETE"),    //         0x2E
	_T("HELP"),  //           0x2F

	/*
	* VK_0 - VK_9 are the same as ASCII '0' - '9' (0x30 - 0x39)
	*/
	_T("0"), //
	_T("1"), //
	_T("2"), //
	_T("3"), //
	_T("4"), //
	_T("5"), //
	_T("6"), //
	_T("7"), //
	_T("8"), //
	_T("9"), //

	_T("reserved"),  //
	_T("reserved"),  //
	_T("reserved"),  //
	_T("reserved"),  //
	_T("reserved"),  //
	_T("reserved"),  //
	/*
	* 0x40 : unassigned
	*/
	_T("unassigned"),    //

	/*
	* VK_A - VK_Z are the same as ASCII 'A' - 'Z' (0x41 - 0x5A)
	*/
	_T("A"), //
	_T("B"), //
	_T("C"), //
	_T("D"), //
	_T("E"), //
	_T("F"), //
	_T("G"), //
	_T("H"), //
	_T("I"), //
	_T("J"), //
	_T("K"), //
	_T("L"), //
	_T("M"), //
	_T("N"), //
	_T("O"), //
	_T("P"), //
	_T("Q"), //
	_T("R"), //
	_T("S"), //
	_T("T"), //
	_T("U"), //
	_T("V"), //
	_T("W"), //
	_T("X"), //
	_T("Y"), //
	_T("Z"), //

	_T("LWIN"),   //           0x5B
	_T("RWIN"),   //           0x5C
	_T("APPS"),   //           0x5D

	/*
	* 0x5E : reserved
	*/
	_T("reserved"),  //

	_T("SLEEP"), //          0x5F

	_T("NUMPAD0"),   //        0x60
	_T("NUMPAD1"),   //        0x61
	_T("NUMPAD2"),   //        0x62
	_T("NUMPAD3"),   //        0x63
	_T("NUMPAD4"),   //        0x64
	_T("NUMPAD5"),   //        0x65
	_T("NUMPAD6"),   //        0x66
	_T("NUMPAD7"),   //        0x67
	_T("NUMPAD8"),   //        0x68
	_T("NUMPAD9"),   //        0x69
	_T("MULTIPLY"),  //       0x6A
	_T("ADD"),   //            0x6B
	_T("SEPARATOR"), //      0x6C
	_T("SUBTRACT"),  //       0x6D
	_T("DECIMAL"),   //        0x6E
	_T("DIVIDE"),    //         0x6F
	_T("F1"),    //             0x70
	_T("F2"),    //             0x71
	_T("F3"),    //             0x72
	_T("F4"),    //             0x73
	_T("F5"),    //             0x74
	_T("F6"),    //             0x75
	_T("F7"),    //             0x76
	_T("F8"),    //             0x77
	_T("F9"),    //             0x78
	_T("F10"),   //            0x79
	_T("F11"),   //            0x7A
	_T("F12"),   //            0x7B
	_T("F13"),   //            0x7C
	_T("F14"),   //            0x7D
	_T("F15"),   //            0x7E
	_T("F16"),   //            0x7F
	_T("F17"),   //            0x80
	_T("F18"),   //            0x81
	_T("F19"),   //            0x82
	_T("F20"),   //            0x83
	_T("F21"),   //            0x84
	_T("F22"),   //            0x85
	_T("F23"),   //            0x86
	_T("F24"),   //            0x87

	/*
	* 0x88 - 0x8F : unassigned
	*/
	_T("unassigned"),    //
	_T("unassigned"),    //
	_T("unassigned"),    //
	_T("unassigned"),    //
	_T("unassigned"),    //
	_T("unassigned"),    //
	_T("unassigned"),    //
	_T("unassigned"),    //

	_T("NUMLOCK"),   //        0x90
	_T("SCROLL"),    //         0x91

	/*
	* NEC PC-9800 kbd definitions
	*/
	//_T("OEM_NEC_EQUAL"), //  0x92   // '=' key on numpad

	/*
	* Fujitsu/OASYS kbd definitions
	*/
	_T("OEM_FJ_JISHO"),  //   0x92   // 'Dictionary' key
	_T("OEM_FJ_MASSHOU"),    // 0x93   // 'Unregister word' key
	_T("OEM_FJ_TOUROKU"),    // 0x94   // 'Register word' key
	_T("OEM_FJ_LOYA"),   //    0x95   // 'Left OYAYUBI' key
	_T("OEM_FJ_ROYA"),   //    0x96   // 'Right OYAYUBI' key

	/*
	* 0x97 - 0x9F : unassigned
	*/
	_T("unassigned"),    //
	_T("unassigned"),    //
	_T("unassigned"),    //
	_T("unassigned"),    //
	_T("unassigned"),    //
	_T("unassigned"),    //
	_T("unassigned"),    //
	_T("unassigned"),    //
	_T("unassigned"),    //

	/*
	* VK_L* & VK_R* - left and right Alt, Ctrl and Shift virtual keys.
	* Used only as parameters to GetAsyncKeyState() and GetKeyState().
	* No other API or message will distinguish left and right keys in this way.
	*/
	_T("LSHIFT"),    //         0xA0
	_T("RSHIFT"),    //         0xA1
	_T("LCONTROL"),  //       0xA2
	_T("RCONTROL"),  //       0xA3
	_T("LMENU"), //          0xA4
	_T("RMENU"), //          0xA5

	_T("BROWSER_BACK"),  //        0xA6
	_T("BROWSER_FORWARD"),   //     0xA7
	_T("BROWSER_REFRESH"),   //     0xA8
	_T("BROWSER_STOP"),  //        0xA9
	_T("BROWSER_SEARCH"),    //      0xAA
	_T("BROWSER_FAVORITES"), //   0xAB
	_T("BROWSER_HOME"),  //        0xAC

	_T("VOLUME_MUTE"),   //         0xAD
	_T("VOLUME_DOWN"),   //         0xAE
	_T("VOLUME_UP"), //           0xAF
	_T("MEDIA_NEXT_TRACK"),  //    0xB0
	_T("MEDIA_PREV_TRACK"),  //    0xB1
	_T("MEDIA_STOP"),    //          0xB2
	_T("MEDIA_PLAY_PAUSE"),  //    0xB3
	_T("LAUNCH_MAIL"),   //         0xB4
	_T("LAUNCH_MEDIA_SELECT"),   // 0xB5
	_T("LAUNCH_APP1"),   //         0xB6
	_T("LAUNCH_APP2"),   //         0xB7


	/*
	* 0xB8 - 0xB9 : reserved
	*/
	_T("reserved"),  //
	_T("reserved"),  //

	_T("OEM_1"), //          0xBA   // ';:' for US
	_T("OEM_PLUS"),  //       0xBB   // '+' any country
	_T("OEM_COMMA"), //      0xBC   // ',' any country
	_T("OEM_MINUS"), //      0xBD   // '-' any country
	_T("OEM_PERIOD"),    //     0xBE   // '.' any country
	_T("OEM_2"), //          0xBF   // '/?' for US
	_T("OEM_3"), //          0xC0   // '`~' for US

	/*
	* 0xC1 - 0xD7 : reserved
	*/
	_T("reserved"),  //
	_T("reserved"),  //
	_T("reserved"),  //
	_T("reserved"),  //
	_T("reserved"),  //
	_T("reserved"),  //
	_T("reserved"),  //
	_T("reserved"),  //
	_T("reserved"),  //
	_T("reserved"),  //
	_T("reserved"),  //
	_T("reserved"),  //
	_T("reserved"),  //
	_T("reserved"),  //
	_T("reserved"),  //
	_T("reserved"),  //
	_T("reserved"),  //
	_T("reserved"),  //
	_T("reserved"),  //
	_T("reserved"),  //
	_T("reserved"),  //
	_T("reserved"),  //
	_T("reserved"),  //

	/*
	* 0xD8 - 0xDA : unassigned
	*/
	_T("unassigned"),    //
	_T("unassigned"),    //
	_T("unassigned"),    //

	_T("OEM_4"), //          0xDB  //  '[{' for US
	_T("OEM_5"), //          0xDC  //  '\|' for US
	_T("OEM_6"), //          0xDD  //  ']}' for US
	_T("OEM_7"), //          0xDE  //  ''"' for US
	_T("OEM_8"), //          0xDF

	/*
	* 0xE0 : reserved
	*/
	_T("reserved"),  //

	/*
	* Various extended or enhanced keyboards
	*/
	_T("OEM_AX"),    //         0xE1  //  'AX' key on Japanese AX kbd
	_T("OEM_102"),   //        0xE2  //  "<>" or "\|" on RT 102-key kbd.
	_T("ICO_HELP"),  //       0xE3  //  Help key on ICO
	_T("ICO_00"),    //         0xE4  //  00 key on ICO

	_T("PROCESSKEY"),    //     0xE5

	_T("ICO_CLEAR"), //      0xE6


	_T("PACKET"),    //         0xE7

	/*
	* 0xE8 : unassigned
	*/
	_T("unassigned"),    //

	/*
	* Nokia/Ericsson definitions
	*/
	_T("OEM_RESET"), //      0xE9
	_T("OEM_JUMP"),  //       0xEA
	_T("OEM_PA1"),   //        0xEB
	_T("OEM_PA2"),   //        0xEC
	_T("OEM_PA3"),   //        0xED
	_T("OEM_WSCTRL"),    //     0xEE
	_T("OEM_CUSEL"), //      0xEF
	_T("OEM_ATTN"),  //       0xF0
	_T("OEM_FINISH"),    //     0xF1
	_T("OEM_COPY"),  //       0xF2
	_T("OEM_AUTO"),  //       0xF3
	_T("OEM_ENLW"),  //       0xF4
	_T("OEM_BACKTAB"),   //    0xF5

	_T("ATTN"),  //           0xF6
	_T("CRSEL"), //          0xF7
	_T("EXSEL"), //          0xF8
	_T("EREOF"), //          0xF9
	_T("PLAY"),  //           0xFA
	_T("ZOOM"),  //           0xFB
	_T("NONAME"),    //         0xFC
	_T("PA1"),   //            0xFD
	_T("OEM_CLEAR"), //      0xFE

	/*
	* 0xFF : reserved
	*/
	_T("reserved")  //
};
#endif
#pragma data_seg()

// global data
UINT g_MOUSE_UWM_HOOK = 0;
UINT g_KEYBOARD_UWM_HOOK = 0;
HINSTANCE g_hIns = NULL;

// local data
static TCHAR buf[BUFSIZ] = {NULL};
static Record record = {NULL};
static const TCHAR appIdFile[]  = _T("app.txt");
LRESULT CALLBACK MouseHookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
	if (nCode < 0)
		return CallNextHookEx(s_hhkMouse, nCode, wParam, lParam);

	if (nCode == HC_ACTION)
	{
		if (s_sHookConf.isKeyUpOnly &&
			(wParam == WM_LBUTTONDOWN || wParam == WM_RBUTTONDOWN || wParam == WM_MBUTTONDOWN || wParam == WM_XBUTTONDOWN ||
			 wParam == WM_NCLBUTTONDOWN || wParam == WM_NCRBUTTONDOWN || wParam == WM_NCMBUTTONDOWN || wParam == WM_NCXBUTTONDOWN))
			return CallNextHookEx(s_hhkMouse, nCode, wParam, lParam);

		PMOUSEHOOKSTRUCT pMouseInfo = (PMOUSEHOOKSTRUCT)lParam;
		if ((wParam == WM_MOUSEMOVE) || (wParam == WM_NCMOUSEMOVE))
		{
			if (s_sHookConf.isTrackMouseMove)
			{
				if (s_sHookConf.isNotifyServer)
					PostMessage(s_hWndServer, g_MOUSE_UWM_HOOK, wParam, MAKELPARAM(pMouseInfo->pt.x, pMouseInfo->pt.y));
				if (s_sHookConf.isLogMouseMove)
				{
					//ZeroMemory(buf, BUFSIZ);
					//_ftprintf(g_fpt, _T("M\t%d\t%d\t%d\r\n"), wParam, pMouseInfo->pt.x, pMouseInfo->pt.y);
					//fflush(g_fpt);
				}
			}
		}
		else
		{
			if (s_sHookConf.isNotifyServer)
				PostMessage(s_hWndServer, g_MOUSE_UWM_HOOK, wParam, MAKELPARAM(pMouseInfo->pt.x, pMouseInfo->pt.y));

			// force log to file for non-mousemove message
			ZeroMemory(buf, BUFSIZ);
			DWORD id = GetCurrentProcessId();
			if (id != s_dwCurrProcId)
			{
				s_dwCurrProcId = id;
				GetModuleFileName(NULL, s_tCurrFileName, MAX_PATH);
			}

			time_t t = time(NULL);
			record.time = t;
			record.type = 0;
			record.app = GetIndex(s_tCurrFileName);
			record.value = wParam&0xF;
			//record.x = (short)pMouseInfo->pt.x;
			//record.y = (short)pMouseInfo->pt.y;
			int a = sizeof(Record);
			CopyMemory(s_tBufIo+s_uBufRecCount, &record, sizeof(Record));
			s_uBufRecCount++;

			if (s_uBufRecCount == BUF_IO_SIZE/sizeof(Record))
			{
				FILE *fp = _tfopen(s_sHookConf.logFile, _T("ab"));	// always success
				fwrite((const void*)&s_tBufIo, sizeof(Record), s_uBufRecCount, fp);
				fclose(fp);
				SaveToFile(s_sHookConf.logFile);
				s_uBufRecCount = 0;
				ZeroMemory(s_tBufIo, BUF_IO_SIZE);
			}
		}
	}
	return CallNextHookEx(s_hhkMouse, nCode, wParam, lParam);
}

LRESULT CALLBACK KeyboardHookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
	if (nCode < 0)
		return CallNextHookEx(s_hhkKeyboard, nCode, wParam, lParam);
	
	if (nCode == HC_ACTION)
	{
		if (s_sHookConf.isKeyUpOnly && !((lParam>>31)&1))
			return CallNextHookEx(s_hhkKeyboard, nCode, wParam, lParam);

		if (s_sHookConf.isNotifyServer)
			PostMessage(s_hWndServer, g_KEYBOARD_UWM_HOOK, wParam, lParam);

		// force log to file for non-mousemove message
		ZeroMemory(buf, BUFSIZ);
		DWORD id = GetCurrentProcessId();
		if (id != s_dwCurrProcId)
		{
			s_dwCurrProcId = id;
			GetModuleFileName(NULL, s_tCurrFileName, MAX_PATH);
		}
		
		time_t t = time(NULL);
		record.time = t;
		record.type = 1;
		record.app = GetIndex(s_tCurrFileName);
		record.value = wParam;
		record.param = ((lParam>>24)&0xFF);
		//record.x = (short)(lParam&0xF);
		//record.y = (short)((lParam>>16)&0xF);
		CopyMemory(s_tBufIo+s_uBufRecCount, &record, sizeof(Record));
		s_uBufRecCount++;

		if (s_uBufRecCount == BUF_IO_SIZE/sizeof(Record))
		{
			FILE *fp = _tfopen(s_sHookConf.logFile, _T("ab"));	// always success
			fwrite((const void*)&s_tBufIo, sizeof(Record), s_uBufRecCount, fp);
			fclose(fp);
			SaveToFile(s_sHookConf.logFile);
			s_uBufRecCount = 0;
			ZeroMemory(s_tBufIo, BUF_IO_SIZE);
		}
	}
	return CallNextHookEx(s_hhkKeyboard, nCode, wParam, lParam);
}

HOOK_API BOOL InstallHook(HWND hWnd)
{
	InitFromFile(s_sHookConf.logFile);

	if (s_sHookConf.isHookMouse)
	{
		s_hhkMouse = SetWindowsHookEx(WH_MOUSE, MouseHookProc, g_hIns, 0);
		if (s_hhkMouse == NULL)
			s_sHookConf.isHookMouse = FALSE;
	}
	if (s_sHookConf.isHookKeyboard)
	{
		s_hhkKeyboard = SetWindowsHookEx(WH_KEYBOARD, KeyboardHookProc, g_hIns, 0);
		if (s_hhkKeyboard == NULL)
			s_sHookConf.isHookKeyboard = FALSE;
	}
	if (!s_sHookConf.isHookMouse && !s_sHookConf.isHookKeyboard)
	{
		ClearFileList();
		return FALSE;
	}

	s_hWndServer = hWnd;
	return TRUE;
}

HOOK_API BOOL UninstallHook()
{
	s_hWndServer = NULL;
	if (s_sHookConf.isHookMouse)
	{
		UnhookWindowsHookEx(s_hhkMouse);
		s_hhkMouse = NULL;
	}
	if (s_sHookConf.isHookKeyboard)
	{
		UnhookWindowsHookEx(s_hhkKeyboard);
		s_hhkKeyboard = NULL;
	}

	FILE *fp = _tfopen(s_sHookConf.logFile, _T("ab"));	// always success
	fwrite((const void*)&s_tBufIo, sizeof(Record), s_uBufRecCount, fp);
	fclose(fp);

	//if (g_fpb)
	//{
	//	fwrite((const void*)&s_tBufIo, sizeof(Record), s_uBufRecCount, g_fpb);
	//	fflush(g_fpb);
	//	fclose(g_fpb);
	//	g_fpb = NULL;
	//}
	//if (g_fpt)
	//{
	//	_ftprintf(g_fpt, _T("%s"), s_tBufIo);
	//	fflush(g_fpt);
	//	fclose(g_fpt);
	//	g_fpt = NULL;
	//}

	SaveToFile(s_sHookConf.logFile);
	return TRUE;
}

//HOOK_API void SetWndServer(HWND hWnd)
//{
//	s_hWndServer = hWnd;
//}

HOOK_API void SetConf(PHookConf pConf)
{
	if (!lstrcmp(pConf->logFile, _T("")))
		lstrcpy(pConf->logFile, s_sHookConf.logFile);
	CopyMemory(&s_sHookConf, pConf, sizeof(HookConf));
}